/*
 * scalar.h
 *
 *  Created on: Sep 17, 2008
 *      Author: lindenb
 */
#include <assert.h>
#include "lang/morestring.h"
#include "lang/morestdlib.h"
#include "util/debug.h"
#include "lexyacc/scalar.h"

#define FORMAT_DOUBLE "%f"
#define FORMAT_INT "%d"
#define SCALAR_ERROR (-9999)

static ScalarPtr scalarNew()
	{
	return  Calloc(1,sizeof(Scalar));
	}

 ScalarPtr  ScalarNewString(const char *s)
	 {
	 ScalarPtr ptr= scalarNew();
	 assert(s!=NULL);
	 if(ptr==NULL) return NULL;

	 ptr->value.string= strdup(s);
	 if( ptr->value.string==NULL)
		 {
		 Free(ptr);
		 return NULL;
		 }

	 ptr->type = SCALAR_IS_STRING;
	 return ptr;
	 }

 ScalarPtr  ScalarNewDouble(scalar_double_t d)
	 {
	 ScalarPtr ptr= scalarNew();
	 ptr->value.floating=d;
	 ptr->type = SCALAR_IS_FLOATING;
	 return ptr;
	 }
 ScalarPtr  ScalarNewInt(scalar_int_t L)
	 {
	 ScalarPtr ptr= scalarNew();
	 ptr->value.integer=L;
	 ptr->type = SCALAR_IS_INTEGER;
	 return ptr;
	 }

 void ScalarDelete(ScalarPtr ptr)
	 {
	 if(ptr==NULL) return ;
	 if(ptr->type==SCALAR_IS_STRING )
		 {
		 Free(ptr->value.string);
		 }
	 Free(ptr);
	 }

 ScalarPtr ScalarClone(const ScalarPtr ptr)
	 {
	 if(ptr==NULL) return NULL;
	 switch(ptr->type)
		 {
		 case SCALAR_IS_INTEGER: return ScalarNewInt(ptr->value.integer);
		 case SCALAR_IS_FLOATING: return ScalarNewDouble(ptr->value.floating);
		 case SCALAR_IS_STRING:  return ScalarNewString(ptr->value.string);
		 }
	 return NULL;
	 }

 int ScalarCompare(const ScalarPtr a, const ScalarPtr b)
	 {
	 scalar_double_t d;
	 scalar_int_t i;
	 malloc_string str;
	 if(a==NULL && b!=NULL) return -1;
	 if(a!=NULL && b==NULL) return 1;
	 if(a==NULL && b==NULL) return 0;

	 switch(a->type)
		 {
		 case SCALAR_IS_INTEGER:
			 switch(b->type)
				 {
				 case SCALAR_IS_INTEGER:
					 i= a->value.integer - b->value.integer;
					 return (i==0?0:i<0?-1:1);
				 case SCALAR_IS_FLOATING:
					 d= (scalar_double_t)a->value.integer - b->value.floating;
					 return (d==0?0:d<0?-1:1);
				 case SCALAR_IS_STRING:
					 str = strfmt(FORMAT_INT,a->value.integer);
					 if(str==NULL) return SCALAR_ERROR;
					 i= strcasecmp(str,b->value.string);
					 Free(str);
					 return (i==0?0:i<0?-1:1);
				 default: return SCALAR_ERROR;
				 }
			 break;
		 case SCALAR_IS_FLOATING:
			 switch(b->type)
				 {
				 case SCALAR_IS_INTEGER:
					 d=a->value.floating -  (scalar_double_t)b->value.integer;
					return (d==0?0:d<0?-1:1);
				 case SCALAR_IS_FLOATING:
					 d=a->value.floating - b->value.floating;
					 return (d==0?0:d<0?-1:1);
				 case SCALAR_IS_STRING:
					 str = strfmt(FORMAT_DOUBLE,a->value.floating);
					 if(str==NULL) return SCALAR_ERROR;
					 i= strcasecmp(str,b->value.string);
					 Free(str);
					 return (i==0?0:i<0?-1:1);
				 default: return SCALAR_ERROR;
				 }
			 break;
		 case SCALAR_IS_STRING:
			 switch(b->type)
				 {
				 case SCALAR_IS_INTEGER:
					 str = strfmt(FORMAT_INT,b->value.integer);
					 if(str==NULL) return SCALAR_ERROR;
					 i= strcasecmp(a->value.string,str);
					 Free(str);
					 return (i==0?0:i<0?-1:1);
				 case SCALAR_IS_FLOATING:
					 str = strfmt(FORMAT_DOUBLE,b->value.floating);
					 if(str==NULL) return SCALAR_ERROR;
					 i= strcasecmp(a->value.string,str);
					 Free(str);
					 return (i==0?0:i<0?-1:1);
				 case SCALAR_IS_STRING:
					 i= strcasecmp(a->value.string,b->value.string);
					 return (i==0?0:i<0?-1:1);
				 default: return SCALAR_ERROR;
				 }
			 break;
		 }
	 assert(0);
	 return SCALAR_ERROR;
	 }

int ScalarPrint(const ScalarPtr ptr,FILE* out)
	{
	if(ptr==NULL)
		{
		fputs("null",out);
		}
	else
		{
		 switch(ptr->type)
			 {
			 case SCALAR_IS_INTEGER:  fprintf(out,FORMAT_INT,ptr->value.integer); break;
			 case SCALAR_IS_FLOATING:  fprintf(out,FORMAT_DOUBLE,ptr->value.floating); break;
			 case SCALAR_IS_STRING: fputc('\"',out);strPrintEscape(ptr->value.string,out);putc('\"',out); break;
			 default:assert(0);break;
			 }
		}
	return 0;
	}
